package com.cci.kangdao.utilTool;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cci.kangdao.context.ApiApplicationContext;
import com.cci.kangdao.dao.SMSUserReplyRecordTDao;
import com.cci.kangdao.dao.SMSUserTDListTDao;
import com.cci.kangdao.dao.model.SMSUserReplyRecordT;
import com.cci.kangdao.dao.model.SMSUserTDListT;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author linjiankun
 * @date 2022/8/3 13:15
 * 蓝云短信平台
 */
public class SmsUtils {

    private static Logger logger = Logger.getLogger(SmsUtils.class);
    static Pattern pattern = Pattern.compile("^((\\+86)|(86)|(0086))?[1][0-9]{10}$");

    private static SMSUserTDListTDao smsUserTDListTDao() {
        return ApiApplicationContext.getBean(SMSUserTDListTDao.class);
    }

    private static SMSUserReplyRecordTDao smsUserReplyRecordTDao() {
        return ApiApplicationContext.getBean(SMSUserReplyRecordTDao.class);
    }

    //发送短信接口   (支持退订逻辑)
    public static String sendMessage(String phone,String message) {
        try{
            if(StringUtils.isEmpty(phone)){
                return "00";
            }
            //1.查询退订名单表所有退订的用户手机号
            List<String> tdUserPhoneList = smsUserTDListTDao().getSMSUserTDListTByPhone();
            if(CollectionUtils.isNotEmpty(tdUserPhoneList) && tdUserPhoneList.contains(phone)){   //退订名单存在当前用户，则不推送短信，直接返回成功标记
                return "00";
            }else{   //退订名单不存在当前用户，逻辑如下
                //调用蓝云平台   获取用户回复内容接口
                List<SMSUserReplyRecordT> smsUserReplyRecordTS = getUpSmsList();
                List<String> tdPhoneList = new ArrayList<>();   //保存smsUserReplyRecordTS中所有退订的用户手机号集合
                int currentUserIsTD = 0;   //当前用户是否退订   0：否   1：是
                if(CollectionUtils.isNotEmpty(smsUserReplyRecordTS)){
                    for(SMSUserReplyRecordT smsUserReplyRecordT : smsUserReplyRecordTS){
                        String receivedPhone = smsUserReplyRecordT.getPhoneNumber();
                        String receivedMessage = smsUserReplyRecordT.getMessage();
                        if(StringUtils.isNotEmpty(receivedPhone) && StringUtils.isNotEmpty(receivedMessage) &&
                                (receivedMessage.equals("c") || receivedMessage.equals("C"))){
                            if(!tdPhoneList.contains(receivedPhone)){
                                tdPhoneList.add(receivedPhone);
                            }
                            if(receivedPhone.equals(phone)){
                                currentUserIsTD = 1;
                            }
                        }
                    }
                }
                if(CollectionUtils.isNotEmpty(tdPhoneList)){
                    tdPhoneList.stream().forEach(tdPhone->{
                        if(!tdUserPhoneList.contains(tdPhone)){
                            SMSUserTDListT smsUserTDListT = new SMSUserTDListT();
                            smsUserTDListT.setPhoneNumber(tdPhone);
                            smsUserTDListT.setCreateTime(LocalTimeUtil.getRealCurrentTime());
                            smsUserTDListTDao().insertSelective(smsUserTDListT);
                        }
                    });
                    if(currentUserIsTD == 1){   //当前短信接收人如果退订的话  则直接return   不推送短信
                        return "00";
                    }
                }
            }
            //因为有些推送话术带着结尾标点符号（类似于。或者！）  有些推送话术没带着结尾标点符号
            //所以这里在推送短信前做一波处理   判断最后一位是否是标点符号，不是则拼接。是则不处理
            if(!lastOneIspPunctuation(message)){
                message += "。";
            }
            return sendMultiMessage(message, phone);
        } catch (Exception e){
            logger.error(e.getMessage(), e);
        }
        return "";
    }

    //判断最后一位字符是否是标点符号
    static boolean lastOneIspPunctuation(String str){
        Pattern pattern =  Pattern.compile("[`~!@#$^&*()=|{}':;',\\[\\].<>/?~！@#￥……&*（）——|{}【】‘；：”“'。，、？]$");
        return pattern.matcher(str).find();
    }


    //发送短信接口   (正常推送   不退订)   注册，发送验证码等等这些功能哪怕用户退订了，也会照常发送短信
    public static String sendMessageNotTD(String phone,String message) {
        if(StringUtils.isEmpty(phone)){
            return "00";
        }
        if(!lastOneIspPunctuation(message)){
            message += "。";
        }
        return sendMultiMessageNormal(message, phone);
    }


    //外部系统调用本系统    发送短信接口    只返回是否需要发送短信（-1：否    1：是），发送短信的工作由外部系统自己推送
    public static String outSystemSendMessage(String phone,String message) {
        //sendMessage( phone, message);
        if(StringUtils.isEmpty(phone)){
            return "-1";
        }
        //1.查询退订名单表所有退订的用户手机号
        List<String> tdUserPhoneList = smsUserTDListTDao().getSMSUserTDListTByPhone();
        if(CollectionUtils.isNotEmpty(tdUserPhoneList) && tdUserPhoneList.contains(phone)){   //退订名单存在当前用户，则不推送短信，直接返回成功标记
            return "-1";
        }else{   //退订名单不存在当前用户，逻辑如下
            //调用蓝云平台   获取用户回复内容接口
            List<SMSUserReplyRecordT> smsUserReplyRecordTS = getUpSmsList();
            List<String> tdPhoneList = new ArrayList<>();   //保存smsUserReplyRecordTS中所有退订的用户手机号集合
            int currentUserIsTD = 0;   //当前用户是否退订   0：否   1：是
            if(CollectionUtils.isNotEmpty(smsUserReplyRecordTS)){
                for(SMSUserReplyRecordT smsUserReplyRecordT : smsUserReplyRecordTS){
                    String receivedPhone = smsUserReplyRecordT.getPhoneNumber();
                    String receivedMessage = smsUserReplyRecordT.getMessage();
                    if(StringUtils.isNotEmpty(receivedPhone) && StringUtils.isNotEmpty(receivedMessage) &&
                            (receivedMessage.equals("c") || receivedMessage.equals("C"))){
                        if(!tdPhoneList.contains(receivedPhone)){
                            tdPhoneList.add(receivedPhone);
                        }
                        if(receivedPhone.equals(phone)){
                            currentUserIsTD = 1;
                        }
                    }
                }
            }
            if(CollectionUtils.isNotEmpty(tdPhoneList)){
                tdPhoneList.stream().forEach(tdPhone->{
                    if(!tdUserPhoneList.contains(tdPhone)){
                        SMSUserTDListT smsUserTDListT = new SMSUserTDListT();
                        smsUserTDListT.setPhoneNumber(tdPhone);
                        smsUserTDListT.setCreateTime(LocalTimeUtil.getRealCurrentTime());
                        smsUserTDListTDao().insertSelective(smsUserTDListT);
                    }
                });
                if(currentUserIsTD == 1){   //当前短信接收人如果退订的话  则直接return   不推送短信
                    return "-1";
                }
            }
        }
        return "1";
    }


    //退订的短信
    public static String sendMultiMessage(String message, String... phones) {
        try {
            // 拼装短信内容信息
            String smsMessage = prepareSmsMessage(message,phones);
            if(StringUtils.isEmpty(smsMessage)){
                return "00";
            }

            // 获取配置参数
            String accountName = PropertiesUtil.getProperties("projectconfig.properties", "sms.accountName");
            String host = PropertiesUtil.getProperties("projectconfig.properties", "sms.host");
            String apiVersion = PropertiesUtil.getProperties("projectconfig.properties", "sms.apiVersion");
            // 拼接URL
            String url = String.format("%s/services/sms/messages?api-version=%s", host, apiVersion);
            // 拼装Header请求头
            Header account = new BasicHeader("Account", accountName);
            // 拼装token信息
            String token = prepareSharedAccessToken();
            Header authorization = new BasicHeader("Authorization", token);
            //Header accept = new BasicHeader("Accept", "application/json");
            //Header contentType =  new BasicHeader("content-type", "application/json");
            logger.info("发送短信前，message:"+message+",phone:"+Arrays.asList(phones));
            String response = HttpUtils.postJson(url, smsMessage, new ResponseHandler<String>() {
                @Override
                public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
                    if (response.getStatusLine().getStatusCode() == 200) {
                        HttpEntity httpEntity = response.getEntity();
                        return EntityUtils.toString(httpEntity, "UTF-8");
                    } else {
                        logger.error("SMSUtils Http Exception:" + response);
                        return "ERR 短信发送失败";
                    }
                }
            }, account, authorization);
            logger.info("发送短信后，http响应："+response);
            //这里返回值为了兼容之前短信平台逻辑做了变动，当短信接口调用成功后，不返回response，返回字符串"00"
            if(StringUtils.isNotEmpty(response)){
                try {
                    JSONObject j = JSONObject.parseObject(response);
                    String messageId = j.getString("messageId");
                    String sendTime = j.getString("sendTime");
                    if(StringUtils.isNotEmpty(messageId) && StringUtils.isNotEmpty(sendTime)){
                        return "00";
                    }
                }catch (Exception e){
                    return response;
                }
            }
            return response;
        } catch (Exception e) {
            logger.error("SMSUtils Http Exception:",e);
            return "ERR 短信发送失败";
        }
    }

    //组装退订的短信接口信息
    private static String prepareSmsMessage(String message,String... phones){
        SmsMessage smsMessage = new SmsMessage();
        List<String> phoneList = Arrays.asList(phones);
        phoneList = phoneList.stream().filter(phone->pattern.matcher(phone).matches()).collect(Collectors.toList());
        smsMessage.setPhoneNumber(phoneList);
        smsMessage.setExtend("09");
        SmsMessage.MessageBody messageBody = new SmsMessage.MessageBody();
        String templateName = PropertiesUtil.getProperties("projectconfig.properties", "sms.templateName");
        messageBody.setTemplateName(templateName);
        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("message",message);
        messageBody.setTemplateParam(paramMap);
        smsMessage.setMessageBody(messageBody);
        return CollectionUtils.isEmpty(phoneList)?"":JsonUtils.toJsonString(smsMessage);
    }



    //不退订的短信
    public static String sendMultiMessageNormal(String message, String... phones) {
        try {
            // 拼装短信内容信息
            String smsMessage = prepareSmsMessageNormal(message,phones);
            if(StringUtils.isEmpty(smsMessage)){
                return "00";
            }

            // 获取配置参数
            String accountName = PropertiesUtil.getProperties("projectconfig.properties", "sms.accountName");
            String host = PropertiesUtil.getProperties("projectconfig.properties", "sms.host");
            String apiVersion = PropertiesUtil.getProperties("projectconfig.properties", "sms.apiVersion");
            // 拼接URL
            String url = String.format("%s/services/sms/messages?api-version=%s", host, apiVersion);
            // 拼装Header请求头
            Header account = new BasicHeader("Account", accountName);
            // 拼装token信息
            String token = prepareSharedAccessToken();
            Header authorization = new BasicHeader("Authorization", token);
            //Header accept = new BasicHeader("Accept", "application/json");
            //Header contentType =  new BasicHeader("content-type", "application/json");
            logger.info("发送短信前，message:"+message+",phone:"+Arrays.asList(phones));
            String response = HttpUtils.postJson(url, smsMessage, new ResponseHandler<String>() {
                @Override
                public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
                    if (response.getStatusLine().getStatusCode() == 200) {
                        HttpEntity httpEntity = response.getEntity();
                        return EntityUtils.toString(httpEntity, "UTF-8");
                    } else {
                        logger.error("SMSUtils Http Exception:" + response);
                        return "ERR 短信发送失败";
                    }
                }
            }, account, authorization);
            logger.info("发送短信后，http响应："+response);
            //这里返回值为了兼容之前短信平台逻辑做了变动，当短信接口调用成功后，不返回response，返回字符串"00"
            if(StringUtils.isNotEmpty(response)){
                try {
                    JSONObject j = JSONObject.parseObject(response);
                    String messageId = j.getString("messageId");
                    String sendTime = j.getString("sendTime");
                    if(StringUtils.isNotEmpty(messageId) && StringUtils.isNotEmpty(sendTime)){
                        return "00";
                    }
                }catch (Exception e){
                    return response;
                }
            }
            return response;
        } catch (Exception e) {
            logger.error("SMSUtils Http Exception:",e);
            return "ERR 短信发送失败";
        }
    }

    //组装不退订的短信接口信息
    private static String prepareSmsMessageNormal(String message,String... phones){
        SmsMessage smsMessage = new SmsMessage();
        List<String> phoneList = Arrays.asList(phones);
        phoneList = phoneList.stream().filter(phone->pattern.matcher(phone).matches()).collect(Collectors.toList());
        smsMessage.setPhoneNumber(phoneList);
        smsMessage.setExtend("09");
        SmsMessage.MessageBody messageBody = new SmsMessage.MessageBody();
        String templateName = PropertiesUtil.getProperties("projectconfig.properties", "sms.templateNameNormal");
        messageBody.setTemplateName(templateName);
        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("message",message);
        messageBody.setTemplateParam(paramMap);
        smsMessage.setMessageBody(messageBody);
        return CollectionUtils.isEmpty(phoneList)?"":JsonUtils.toJsonString(smsMessage);
    }

    private final static int TIME_TO_EXPIRED_IN_MINS = 20;
    private final static String SCHEMA = "SharedAccessSignature";
    private final static String SIGN_KEY = "sig";
    private final static String KEY_NAME_KEY = "skn";
    private final static String EXPIRY_KEY = "se";

    public static String prepareSharedAccessToken() {
        String sasKey = PropertiesUtil.getProperties("projectconfig.properties", "sms.sasKey");
        String sasKeyName = PropertiesUtil.getProperties("projectconfig.properties", "sms.sasKeyName");
        long totalSeconds = System.currentTimeMillis() / 1000 + TIME_TO_EXPIRED_IN_MINS * 60;
        String expiresOn = String.valueOf(totalSeconds);
        StringBuilder signContent = new StringBuilder();
        signContent
                .append(EXPIRY_KEY)
                .append("=")
                .append(urlEncode(expiresOn))
                .append("&")
                .append(KEY_NAME_KEY)
                .append("=")
                .append(urlEncode(sasKeyName));
        String signature = signString(sasKey, String.valueOf(signContent));
        StringBuilder builder = new StringBuilder();
        builder
                .append(SCHEMA)
                .append(" ")
                .append(SIGN_KEY)
                .append("=")
                .append(signature)
                .append("&")
                .append(signContent);
        return String.valueOf(builder);
    }

    private static String signString(String secret, String message) {
        try {
            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
            sha256_HMAC.init(secret_key);

            String hash = Base64.getEncoder().encodeToString(sha256_HMAC.doFinal(message.getBytes())).trim();
            return urlEncode(hash);
        } catch (Exception e) {
            // Log.e(CEF_LOG, e.toString());
        }
        return "";
    }

    private static String urlEncode(String paramString) {
        if (StringUtils.isEmpty(paramString)) {
            return "";
        }

        try {
            String str = new String(paramString.getBytes(), StandardCharsets.UTF_8);
            str = URLEncoder.encode(str, "UTF-8");
            return str;
        } catch (Exception exception) {
            //  Log.e(CEF_LOG, localException.toString());
        }
        return "";
    }


    //获取上行短信接口
    public static List<SMSUserReplyRecordT> getUpSmsList(){
        List<SMSUserReplyRecordT> smsUserReplyRecordTS = new ArrayList<>();
        try{
            // 获取配置参数
            String accountName = PropertiesUtil.getProperties("projectconfig.properties", "sms.accountName");
            String getUpSmsListUrl = PropertiesUtil.getProperties("projectconfig.properties", "sms.getUpSmsListUrl");
            String apiVersion = PropertiesUtil.getProperties("projectconfig.properties", "sms.apiVersion");
            // 拼接URL
            String url = String.format(getUpSmsListUrl+"%s", apiVersion);
            // 拼装Header请求头
            Header account = new BasicHeader("Account", accountName);
            // 拼装token信息
            String token = prepareSharedAccessToken();
            Header authorization = new BasicHeader("Authorization", token);
            String response = HttpUtils.get(url, new ResponseHandler<String>() {
                @Override
                public String handleResponse(HttpResponse response) throws IOException {
                    if (response.getStatusLine().getStatusCode() == 200) {
                        HttpEntity httpEntity = response.getEntity();
                        return EntityUtils.toString(httpEntity, "UTF-8");
                    } else {
                        logger.error("调用上行短信内容接口异常，响应:" + response);
                        return "";
                    }
                }
            }, account, authorization);
            if(StringUtils.isNotEmpty(response)){
                JSONArray jsonArray = JSONArray.parseArray(response);
                smsUserReplyRecordTS = jsonArray.toJavaList(SMSUserReplyRecordT.class);
                if(CollectionUtils.isNotEmpty(smsUserReplyRecordTS)){
                    smsUserReplyRecordTS.stream().forEach(smsUserReplyRecordT -> {
                        smsUserReplyRecordT.setCreateTime(LocalTimeUtil.getRealCurrentTime());
                    });
                    smsUserReplyRecordTDao().batchInsert(smsUserReplyRecordTS);
                }
            }

        } catch (Exception e){
            logger.error(e.getMessage(), e);
        }
        return smsUserReplyRecordTS;
    }


    public static void main(String[] args) {
        String res = SmsUtils.sendMessageNotTD("15230112379","test这是短信内容33!");
        System.out.println(res);
        System.out.println(prepareSharedAccessToken());
    }
}
